package cn.jingyuan.owl.utils.core.codec;

import cn.jingyuan.owl.utils.core.CharsetUtils;
import cn.jingyuan.owl.utils.core.io.FileUtils;
import cn.jingyuan.owl.utils.core.io.IoUtils;

import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;

/**
 * Base64 工具类，提供 Base64 的编码和解码方案<br>
 * base64 编码是用 64（2 的 6 次方）个 ASCII 字符来表示 256（2 的 8 次方）个 ASCII 字符，也就是三位二进制数组经过编码后变为四位的 ASCII 字符显示，长度比原来增加 1/3
 */
public class Base64 {

    /**
     * 编码为 Base64，非 URL 安全的
     *
     * @param arr 被编码的数组
     * @param lineSep 在 76 个 char 之后是 CRLF 还是 EOF
     *
     * @return 编码后的 bytes
     */
    public static byte[] encode(byte[] arr, boolean lineSep) {
        return Base64Encoder.encode(arr, lineSep);
    }

    /**
     * 编码为 Base64，URL 安全的
     *
     * @param arr 被编码的数组
     * @param lineSep 在 76 个 char 之后是 CRLF 还是 EOF
     *
     * @return 编码后的 bytes
     */
    public static byte[] encodeUrlSafe(byte[] arr, boolean lineSep) {
        return Base64Encoder.encodeUrlSafe(arr, lineSep);
    }

    /**
     * base64 编码
     *
     * @param source 被编码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static String encode(CharSequence source) {
        return Base64Encoder.encode(source);
    }

    /**
     * base64 编码，URL 安全
     *
     * @param source 被编码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static String encodeUrlSafe(CharSequence source) {
        return Base64Encoder.encodeUrlSafe(source);
    }

    /**
     * base64 编码
     *
     * @param source 被编码的 base64 字符串
     * @param charset 字符集
     *
     * @return 被加密后的字符串
     */
    public static String encode(CharSequence source, String charset) {
        return Base64Encoder.encode(source, CharsetUtils.charset(charset));
    }

    /**
     * base64 编码，URL 安全
     *
     * @param source 被编码的 base64 字符串
     * @param charset 字符集
     *
     * @return 被加密后的字符串
     */
    public static String encodeUrlSafe(CharSequence source, String charset) {
        return Base64Encoder.encodeUrlSafe(source, CharsetUtils.charset(charset));
    }

    /**
     * base64 编码
     *
     * @param source 被编码的 base64 字符串
     * @param charset 字符集
     *
     * @return 被加密后的字符串
     */
    public static String encode(CharSequence source, Charset charset) {
        return Base64Encoder.encode(source, charset);
    }

    /**
     * base64 编码，URL 安全的
     *
     * @param source 被编码的 base64 字符串
     * @param charset 字符集
     *
     * @return 被加密后的字符串
     */
    public static String encodeUrlSafe(CharSequence source, Charset charset) {
        return Base64Encoder.encodeUrlSafe(source, charset);
    }

    /**
     * base64 编码
     *
     * @param source 被编码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static String encode(byte[] source) {
        return Base64Encoder.encode(source);
    }

    /**
     * base64 编码,URL 安全的
     *
     * @param source 被编码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static String encodeUrlSafe(byte[] source) {
        return Base64Encoder.encodeUrlSafe(source);
    }

    /**
     * base64 编码
     *
     * @param in 被编码 base64 的流（一般为图片流或者文件流）
     *
     * @return 被加密后的字符串
     */
    public static String encode(InputStream in) {
        return Base64Encoder.encode(IoUtils.readBytes(in));
    }

    /**
     * base64 编码,URL 安全的
     *
     * @param in 被编码 base64 的流（一般为图片流或者文件流）
     *
     * @return 被加密后的字符串
     */
    public static String encodeUrlSafe(InputStream in) {
        return Base64Encoder.encodeUrlSafe(IoUtils.readBytes(in));
    }

    /**
     * base64 编码
     *
     * @param file 被编码 base64 的文件
     *
     * @return 被加密后的字符串
     */
    public static String encode(File file) {
        return Base64Encoder.encode(FileUtils.readBytes(file));
    }

    /**
     * base64 编码,URL 安全的
     *
     * @param file 被编码 base64 的文件
     *
     * @return 被加密后的字符串
     */
    public static String encodeUrlSafe(File file) {
        return Base64Encoder.encodeUrlSafe(FileUtils.readBytes(file));
    }

    /**
     * 编码为 Base64<br>
     * 如果 isMultiLine 为<code>true</code>，则每 76 个字符一个换行符，否则在一行显示
     *
     * @param arr 被编码的数组
     * @param isMultiLine 在 76 个 char 之后是 CRLF 还是 EOF
     * @param isUrlSafe 是否使用 URL 安全字符，一般为<code>false</code>
     *
     * @return 编码后的 bytes
     */
    public static byte[] encode(byte[] arr, boolean isMultiLine, boolean isUrlSafe) {
        return Base64Encoder.encode(arr, isMultiLine, isUrlSafe);
    }

    /**
     * base64 解码
     *
     * @param source 被解码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static String decodeStringGbk(CharSequence source) {
        return Base64Decoder.decodeString(source, CharsetUtils.CHARSET_GBK);
    }

    /**
     * base64 解码
     *
     * @param source 被解码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static String decodeString(CharSequence source) {
        return Base64Decoder.decodeString(source);
    }

    /**
     * base64 解码
     *
     * @param source 被解码的 base64 字符串
     * @param charset 字符集
     *
     * @return 被加密后的字符串
     */
    public static String decodeString(CharSequence source, String charset) {
        return Base64Decoder.decodeString(source, CharsetUtils.charset(charset));
    }

    /**
     * base64 解码
     *
     * @param source 被解码的 base64 字符串
     * @param charset 字符集
     *
     * @return 被加密后的字符串
     */
    public static String decodeString(CharSequence source, Charset charset) {
        return Base64Decoder.decodeString(source, charset);
    }

    /**
     * base64 解码
     *
     * @param base64 被解码的 base64 字符串
     * @param destFile 目标文件
     *
     * @return 目标文件
     */
    public static File decodeToFile(CharSequence base64, File destFile) {
        return FileUtils.writeBytes(Base64Decoder.decode(base64), destFile);
    }

    /**
     * base64 解码
     *
     * @param base64 被解码的 base64 字符串
     * @param out 写出到的流
     * @param isCloseOut 是否关闭输出流
     */
    public static void decodeToStream(CharSequence base64, OutputStream out, boolean isCloseOut) {
        IoUtils.write(out, isCloseOut, Base64Decoder.decode(base64));
    }

    /**
     * base64 解码
     *
     * @param base64 被解码的 base64 字符串
     *
     * @return 被加密后的字符串
     */
    public static byte[] decode(CharSequence base64) {
        return Base64Decoder.decode(base64);
    }

    /**
     * 解码 Base64
     *
     * @param in 输入
     *
     * @return 解码后的 bytes
     */
    public static byte[] decode(byte[] in) {
        return Base64Decoder.decode(in);
    }

}
